home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Languages / Caml Light 0.7 / Caml Light 0.7 source / src / lex / lexgen.ml < prev    next >
Text File  |  1995-06-01  |  6KB  |  223 lines

  1. (* Compiling a lexer definition *)
  2.  
  3. #open "syntax";;
  4.  
  5. (* Deep abstract syntax for regular expressions *)
  6.  
  7. type regexp =
  8.     Empty
  9.   | Chars of int
  10.   | Action of int
  11.   | Seq of regexp * regexp
  12.   | Alt of regexp * regexp
  13.   | Star of regexp
  14. ;;
  15.  
  16. (* From shallow to deep syntax *)
  17.  
  18. let chars = ref ([] : char list list);;
  19. let chars_count = ref 0;;
  20. let actions = ref ([] : (int * location) list);;
  21. let actions_count = ref 0;;
  22.  
  23. let rec encode_regexp = function
  24.     Epsilon -> Empty
  25.   | Characters cl ->
  26.       let n = !chars_count in
  27.       chars := cl :: !chars;
  28.       incr chars_count;
  29.       Chars(n)
  30.   | Sequence(r1,r2) ->
  31.       Seq(encode_regexp r1, encode_regexp r2)
  32.   | Alternative(r1,r2) ->
  33.       Alt(encode_regexp r1, encode_regexp r2)
  34.   | Repetition r ->
  35.       Star (encode_regexp r)
  36. ;;
  37.  
  38. let encode_casedef =
  39.   it_list
  40.    (fun reg (expr,act) ->
  41.      let act_num = !actions_count in
  42.      incr actions_count;
  43.      actions := (act_num, act) :: !actions;
  44.      Alt(reg, Seq(encode_regexp expr, Action act_num)))
  45.   Empty
  46. ;;
  47.  
  48. let encode_lexdef (Lexdef(_, ld)) =
  49.   chars := [];
  50.   chars_count := 0;
  51.   actions := [];
  52.   actions_count := 0;
  53.   let name_regexp_list =
  54.     map (fun (name, casedef) -> (name, encode_casedef casedef)) ld in
  55.   let chr = vect_of_list (rev !chars)
  56.   and act = !actions in
  57.   chars := [];
  58.   actions := [];
  59.   (chr, name_regexp_list, act)
  60. ;;
  61.  
  62. (* To generate directly a NFA from a regular expression.
  63.    Confer Aho-Sethi-Ullman, dragon book, chap. 3 *)
  64.  
  65. type transition =
  66.     OnChars of int
  67.   | ToAction of int
  68. ;;
  69.  
  70. let rec merge_trans = fun
  71.     [] s2 -> s2
  72.   | s1 [] -> s1
  73.   | (OnChars n1 as t1 :: r1 as s1) (OnChars n2 as t2 :: r2 as s2) ->
  74.       if n1 == n2 then t1 :: merge_trans r1 r2 else
  75.       if n1 <  n2 then t1 :: merge_trans r1 s2 else
  76.                        t2 :: merge_trans s1 r2
  77.   | (ToAction n1 as t1 :: r1 as s1) (ToAction n2 as t2 :: r2 as s2) ->
  78.       if n1 == n2 then t1 :: merge_trans r1 r2 else
  79.       if n1 <  n2 then t1 :: merge_trans r1 s2 else
  80.                        t2 :: merge_trans s1 r2
  81.   | (OnChars n1 as t1 :: r1 as s1) (ToAction n2 as t2 :: r2 as s2) ->
  82.       t1 :: merge_trans r1 s2
  83.   | (ToAction n1 as t1 :: r1 as s1) (OnChars n2 as t2 :: r2 as s2) ->
  84.       t2 :: merge_trans s1 r2
  85. ;;
  86.  
  87. let rec nullable = function
  88.     Empty      -> true
  89.   | Chars _    -> false
  90.   | Action _   -> false
  91.   | Seq(r1,r2) -> nullable r1 & nullable r2
  92.   | Alt(r1,r2) -> nullable r1 or nullable r2
  93.   | Star r     -> true
  94. ;;
  95.  
  96. let rec firstpos = function
  97.     Empty      -> []
  98.   | Chars pos  -> [OnChars pos]
  99.   | Action act -> [ToAction act]
  100.   | Seq(r1,r2) -> if nullable r1
  101.                   then merge_trans (firstpos r1) (firstpos r2)
  102.                   else firstpos r1
  103.   | Alt(r1,r2) -> merge_trans (firstpos r1) (firstpos r2)
  104.   | Star r     -> firstpos r
  105. ;;
  106.  
  107. let rec lastpos = function
  108.     Empty      -> []
  109.   | Chars pos  -> [OnChars pos]
  110.   | Action act -> [ToAction act]
  111.   | Seq(r1,r2) -> if nullable r2
  112.                   then merge_trans (lastpos r1) (lastpos r2)
  113.                   else lastpos r2
  114.   | Alt(r1,r2) -> merge_trans (lastpos r1) (lastpos r2)
  115.   | Star r     -> lastpos r
  116. ;;
  117.  
  118. let followpos size name_regexp_list =
  119.   let v = make_vect size [] in
  120.     let fill_pos first = function
  121.         OnChars pos -> v.(pos) <- merge_trans first v.(pos); ()
  122.       | ToAction _  -> () in
  123.     let rec fill = function
  124.         Seq(r1,r2) ->
  125.           fill r1; fill r2;
  126.           do_list (fill_pos (firstpos r2)) (lastpos r1)
  127.       | Alt(r1,r2) ->
  128.           fill r1; fill r2
  129.       | Star r ->
  130.           fill r;
  131.           do_list (fill_pos (firstpos r)) (lastpos r)
  132.       | _ -> () in
  133.     do_list (fun (name, regexp) -> fill regexp) name_regexp_list;
  134.     v
  135. ;;
  136.  
  137. let no_action = 32767;;
  138.  
  139. let split_trans_set = it_list
  140.   (fun (act, pos_set as act_pos_set) ->
  141.      function OnChars pos   -> (act, pos :: pos_set)
  142.          |    ToAction act1 -> if act1 < act then (act1, pos_set)
  143.                                              else act_pos_set)
  144.   (no_action, [])
  145. ;;
  146.  
  147. let memory  = (hashtbl__new 131 : (transition list, int) hashtbl__t)
  148. and todo    = ref ([] : (transition list * int) list)
  149. and next    = ref 0
  150. ;;
  151.  
  152. let reset_state_mem () =
  153.   hashtbl__clear memory; todo := []; next := 0; ()
  154. ;;
  155.  
  156. let get_state st = 
  157.   try
  158.     hashtbl__find memory st
  159.   with Not_found ->
  160.     let nbr = !next in
  161.     incr next;
  162.     hashtbl__add memory st nbr;
  163.     todo := (st, nbr) :: !todo;
  164.     nbr
  165. ;;
  166.  
  167. let rec map_on_states f =
  168.   match !todo with
  169.     []  -> []
  170.   | (st,i)::r -> todo := r; let res = f st in (res,i) :: map_on_states f
  171. ;;
  172.  
  173. let number_of_states () =
  174.   !next
  175. ;;
  176.  
  177. let goto_state = function
  178.     [] -> Backtrack
  179.   | ps -> Goto (get_state ps)
  180. ;;
  181.  
  182. let transition_from chars follow pos_set = 
  183.   let tr = make_vect 256 []
  184.   and shift = make_vect 256 Backtrack in
  185.     do_list
  186.       (fun pos ->
  187.         do_list
  188.           (fun c ->
  189.              tr.(int_of_char c) <-
  190.                merge_trans tr.(int_of_char c) follow.(pos))
  191.           chars.(pos))
  192.       pos_set;
  193.     for i = 0 to 255 do
  194.       shift.(i) <- goto_state tr.(i)
  195.     done;
  196.     shift
  197. ;;
  198.  
  199. let translate_state chars follow state =
  200.   match split_trans_set state with
  201.     n, [] -> Perform n
  202.   | n, ps -> Shift( (if n == no_action then No_remember else Remember n),
  203.                     transition_from chars follow ps)
  204. ;;
  205.  
  206. let make_dfa lexdef =
  207.   let (chars, name_regexp_list, actions) =
  208.     encode_lexdef lexdef in
  209.   let follow =
  210.     followpos (vect_length chars) name_regexp_list in
  211.   reset_state_mem();
  212.   let initial_states =
  213.     map (fun (name, regexp) -> (name, get_state(firstpos regexp)))
  214.         name_regexp_list in
  215.   let states =
  216.     map_on_states (translate_state chars follow) in
  217.   let v =
  218.     make_vect (number_of_states()) (Perform 0) in
  219.   do_list (fun (auto, i) -> v.(i) <- auto) states;
  220.   reset_state_mem();
  221.   (initial_states, v, actions)
  222. ;;
  223.